iT邦幫忙

2023 iThome 鐵人賽

DAY 28
0
Modern Web

起步Go!Let's Go!系列 第 28

[ Day 28 ] Go 與 Gin:打造強大的 Web 應用程式 (中)

  • 分享至 

  • xImage
  •  

昨天我們已經學會如何使用 Gin 以及 Gorm,並且在輸入網址 http://loaclhost:8080 可以看到 JSON 格式的 message,接下來,我們將要練習要怎麼 JSON 來傳送我要的資訊,以及建立資料及讀取資料。
在開始之前,大家可以先去看一下 Restful API 以及 如何使用 Postman,之後的文章會用運用到這些知識點。

你的第一則貼文

Gin 與 Gorm

昨天已經有介紹過 Gorm 了,有了它我們就可以開始來做簡易貼文網站了,那他要怎麼運用在 Gin 裡面呢?

package main

import (
	"github.com/gin-gonic/gin"
	"gorm.io/driver/sqlite"
	"gorm.io/gorm"
)

// 建立一個 Post 結構體
type Post struct {
	gorm.Model
	Title   string `json:"title"`
	Content string `json:"content"`
}

func main() {
	// 連接資料庫
	db, err := gorm.Open(sqlite.Open("test.db"), &gorm.Config{})
	if err != nil {
		panic("failed to connect database")
	}
    
    // 自動遷移
	db.AutoMigrate(&Post{})

    // 建立第一筆 Post 資料
	db.Create(&Post{Title: "學習使用 GORM", Content: "先安裝 GORM"})

	r := gin.Default()
    
    //找所有的貼文
	var posts []Post
	db.Find(&posts)

	r.GET("/", func(c *gin.Context) {
		c.JSON(200, gin.H{
			"posts": posts,
		})
	})
    // 啟動 Gin
	r.Run()
}

第一步我們線連接到資料庫。第二步創建一個 Post 結構體。第三建立一個 Post 資料表。最後,建立一筆 Post 的資料。
完成後,執行該程式,並輸入 http://localhost:8080 ,我們就可以看到一筆 Post 的 JSON 資料,如下:
frist post
看到這樣的結果,就代表你成功建立了一筆資料,並且可以得到一筆資料。

整理有益身體健康

我們稍微整理一下剛剛的程式碼,之後再做其他功能時也比較清楚這在做什麼,也比較好閱讀。
我們先建立等一下會用到的資料夾,分別是databasemodelmigration,再來,在這三個資料夾內分別加上等等會用到的檔案,分別是database/db.gomodel/post_model.gomigration/migrate.go,整理完的檔案結構如下:

it-post
 |-- database
 |    |-- db.go
 |
 |-- model
 |    |-- post_model.go
 |
 |-- migration
      |-- migrate.go

database/db.go

我們先到 database/db.go 處理連接資料庫的東西:

// database/db.go
package database

import (
	"gorm.io/driver/sqlite"
	"gorm.io/gorm"
)

var DB *gorm.DB

func ConnectToDB() {
	// 連接 test 資料庫
	var err error
	DB, err = gorm.Open(sqlite.Open("test.db"), &gorm.Config{})
	if err != nil {
		panic("failed to connect database")
	}
}

這邊做了一點小更動,我們將 DB 設為全域變數,方便其他地方也方便使用。

model/post_model.go

我把 Post 這個結構體單獨放置,這樣在之後要看資料表的欄位是什麼也比較方便。

package model

import "gorm.io/gorm"

type Post struct {
	gorm.Model
	Title   string `json:"title"`
	Content string `json:"content"`
}

main.go

原先在 mian.go 的東西也要整理一下,將不必要的東西刪掉。

package main

import (
	"it-post/config"
	"it-post/model"

	"github.com/gin-gonic/gin"
)

func main() {
	database.ConnectToDB()

    r := gin.Default()
    
    // 查詢全部的 post
	var posts []model.Post
	database.DB.Find(&posts)

	r.GET("/", func(c *gin.Context) {
		c.JSON(200, gin.H{
			"posts": posts,
		})
	})
	r.Run() // listen and serve on 0.0.0.0:8080
}

migration/migrate.go

這主要是要建立新的資料表所使用的檔案,所以他會稍稍不一樣:

package main

import (
	"it-post/config"
	"it-post/model"
)

func main() {
    // 連接資料庫
    database.ConnectToDB()
	
    // 執行 Post 的遷移
	err := config.DB.AutoMigrate(&model.Post{})
	if err != nil {
		panic("failed to migrate database")
	}
}

那要怎麼使用呢?我們只要在終端機輸入 go run migration/migrate.go,這樣就可以建立一個 Post 的資料表了。

CRUD 之 C

C 代表著創建 (Create),其實在文章的一開始就已經有偷偷做了這件事,如下:

db.Create(&Post{Title: "學習使用 GORM", Content: "先安裝 GORM"})

這個意思就是在 Post 裡面增加一筆 Title 為 "學習使用 GORM" 以及 Content 為 "先安裝 GORM" 的資料,這個就是最簡單的創建資料的方式,那實際上要怎麼使用,我們到 main() 增加這一段,如下:

// 建立第一篇貼文
r.POST("/posts", func(c *gin.Context) {
    var posts model.Post
    if err := c.ShouldBindJSON(&posts); err != nil {
        c.JSON(http.StatusBadRequest, gin.H{
            "error": "Bad request data",
            return
        })
    }

    if err := database.DB.Create(&posts).Error; err != nil {
        c.JSON(http.StatusInternalServerError, gin.H{
            "error": "Failed to create post",
            return
        })
    }
    c.JSON(http.StatusOK, gin.H{
        "message": "Create post successfully",
    })
})

程式碼解釋:

  • 一開始,先建立設定一個 /posts 的路由,並使用 POST 請求。
  • 宣告一個 posts 變數,主要用來儲存解析後的 JSON 資料。
  • 使用了 Gin 框架的 ShouldBindJSON 方法來解析 POST 請求中的 JSON 資料並存儲到 posts 變數中。如果發生解析錯誤,將會回傳 400 Bad Request 的錯誤訊息給客戶端。
  • 把解析過後的 JSON 資料存到資料庫中,使用 database.DB.Create(&posts) 進行儲存,如果發生了創建錯誤,將會回傳 500 Internal Server Error 的錯誤訊息給客戶端。
  • 最後,過程中如果沒有問題就會回傳回傳 200 OK 的狀態碼給客戶端,並且回傳一個包含成功訊息的 JSON。

打開 Postman,並且輸入 http://127.0.0.1:8080/posts ,接著,輸入你要傳的 JSON 資料,並 Send。
posts
看到這個畫面就代表你成功建立了一則新貼文了。
接著,打開瀏覽器,並輸入 http://127.0.0.1:8080/ ,你會看到這樣的畫面:
browser
為甚麼會有這些東西呢?接下來就要介紹CRUD的第二位角色。

CRUD 之 R

R 代表著讀 (read),其實在一開始也偷偷做了這件事,如下:

var posts []model.Post
database.DB.Find(&posts)

這邊使用了 GORM 中的查找功能,這邊會找到所有的 Post 的資料,並且將其使用 JSON 傳遞出去。
但如果需要找特定資料的話,就需要用到不同的方法,一樣到 main() 增加這麼一段,如下:

r.GET("/posts/:id", func(c *gin.Context) {
    id := c.Param("id")
    var post model.Post

    if err := database.DB.First(&post, id).Error; err != nil{
        c.JSON(http.StatusInternalServerError, gin.H{
            "error": "Failed to fetch posts",
        })
        return
    }

    c.JSON(http.StatusOK, gin.H{
        "post":	post,
    })
})

程式碼解釋:

  • 首先,設置了一個路由 /posts/:id,該路由使用 GET 方法。
  • 宣告了一個名為 post 的變數,用於存儲從資料庫檢索到的文章。
  • 使用了 GORM 中的 First(&post, id) 方法來從資料庫中根據提供的 id 查找並檢索相應的文章。如果出現錯誤,則返回一個內部服務器錯誤(500)的 JSON 回應。
  • 如果成功檢索到文章,則將其作為 JSON 回應返回,狀態碼為 200 OK。

打開 Postman,並且輸入 http://127.0.0.1:8080/posts/1 ,接著,並 Send。
post read
看到這個畫面就代表,你成功找到你要的貼文了。
如果是不存在的貼文呢?假設第三篇貼文,輸入 http://127.0.0.1:8080/posts/2:
not found post
如果找不到貼文,那就會回應 "Failed to fetch posts" 的 JSON 回應。

今天的內容很多,希望大家有看懂,同時我也把今天的內容更新到 Github上,明天將會介紹 CRUD 中剩下的兩個角色。我們明天見。


上一篇
[ Day 27 ] Go 與 Gin:打造強大的 Web 應用程式 (上)
下一篇
[ Day 29 ] Go 與 Gin:打造強大的 Web 應用程式 (下)
系列文
起步Go!Let's Go!30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言